package com.KMGSoftworks.ShoppingList;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class ShoppingListProvider extends ContentProvider {
	
	private static final String TAG = "ShoppingListProvider";
	private static final String DATABASE_NAME = "shopping_list.sqlite";
    private static final int DATABASE_VERSION = 1;
    
    private static HashMap<String,String> sListProjectionMap;
    
    private static final int LIST 			= 1;
    private static final int LIST_ID 		= 2;
    private static final int LIST_ITEM 		= 3;
    private static final int LIST_ITEM_ID 	= 4;
    private static final int ITEM 			= 5;
    private static final int ITEM_ID 		= 6;
    
    private static final UriMatcher sUriMatcher;
    
    private DatabaseHelper dbHelper;
    
    static {
        // Create a new instance
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(ShoppingList.AUTHORITY, "lists", LIST);
        sUriMatcher.addURI(ShoppingList.AUTHORITY, "lists/#", LIST_ID);
        sUriMatcher.addURI(ShoppingList.AUTHORITY, "listitems", LIST_ITEM);
        sUriMatcher.addURI(ShoppingList.AUTHORITY, "listitems/#", LIST_ITEM_ID);
        sUriMatcher.addURI(ShoppingList.AUTHORITY, "items", LIST);
        sUriMatcher.addURI(ShoppingList.AUTHORITY, "items/#", LIST_ID);
    }
    
    static class DatabaseHelper extends SQLiteOpenHelper {
    	private static final String TAG = "DatabaseHelper";
    	
 	   	private static final String CREATE_LISTS = "CREATE TABLE " + 
 	   					ShoppingList.List.TABLE_NAME + "(" + 
 	   					ShoppingList.List._ID + " integer primary key autoincrement, " +
 	   					ShoppingList.List.COLUMN_NAME_NAME + " text not null," +
 	   					ShoppingList.List.COLUMN_NAME_COUNT + " integer default 0)";
 	   
 	   	private static final String CREATE_LISTITEMS = "CREATE TABLE " +
	   					ShoppingList.ListItem.TABLE_NAME +  "(" +
	   					ShoppingList.ListItem.COLUMN_NAME_LIST_ID + " integer not null, " +
	   					ShoppingList.ListItem.COLUMN_NAME_ITEM_ID + " integer not null, " +
	   					ShoppingList.ListItem.COLUMN_NAME_COUNT + " integer default 0, " +
	   					"PRIMARY KEY (" + ShoppingList.ListItem.COLUMN_NAME_LIST_ID + "," + ShoppingList.ListItem.COLUMN_NAME_ITEM_ID + ") " +
	   					"FOREIGN KEY (" + ShoppingList.ListItem.COLUMN_NAME_LIST_ID + ") REFERENCES lists (" + ShoppingList.List._ID + ") " +
	   					"FOREIGN KEY (" + ShoppingList.ListItem.COLUMN_NAME_ITEM_ID + ") REFERENCES items (" + ShoppingList.Item._ID + "))";

 	   	private static final String CREATE_ITEMS = "CREATE TABLE " +
						ShoppingList.Item.TABLE_NAME +  "(" +
						ShoppingList.Item._ID + " integer primary key autoincrement, " +
						ShoppingList.Item.COLUMN_NAME_ITEM_NAME + " text not null)";
 	   	
 	   	public static final String LISTITEMS_JOIN_ITEMS = "listitems JOIN items ON (listitems.itemID = items._ID)";
 	   	public static final String LIST_JOIN_LISTITEMS = "list JOIN listitems ON (list._ID = listitems.listID)";
	   
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
        	Log.i(TAG, "Creating database");
	        db.execSQL(CREATE_LISTS);
	        db.execSQL(CREATE_ITEMS);
	        db.execSQL(CREATE_LISTITEMS);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

            // Logs that the database is being upgraded
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");

	         db.execSQL("DROP TABLE IF EXISTS listitems");
	         db.execSQL("DROP TABLE IF EXISTS lists");
	         db.execSQL("DROP TABLE IF EXISTS items");
	         onCreate(db);
        }
    }
    
	@Override
	public boolean onCreate() {
		dbHelper = new DatabaseHelper(getContext());
		return true;
	}
    
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {

		SQLiteDatabase db = dbHelper.getWritableDatabase();
		String finalSelection;
		int count;
		
		switch(sUriMatcher.match(uri)){
			case LIST:
				count = db.delete(ShoppingList.List.TABLE_NAME, selection, selectionArgs);
				break;
			case LIST_ID:
				finalSelection = ShoppingList.List._ID + " = " + uri.getPathSegments().get(ShoppingList.List.LIST_ID_PATH_POSITION);
				if(selection != null){
					finalSelection =finalSelection + " AND " + selection;
				}
				count = db.delete(ShoppingList.List.TABLE_NAME, finalSelection, selectionArgs);
				break;
			case LIST_ITEM:
				count = db.delete(ShoppingList.ListItem.TABLE_NAME, selection, selectionArgs);
				break;
			case LIST_ITEM_ID:
				finalSelection = ShoppingList.ListItem._ID + " = " + uri.getPathSegments().get(ShoppingList.ListItem.ID_PATH_POSITION);
				if(selection != null){
					finalSelection = finalSelection + " AND " + selection;
				}
				count = db.delete(ShoppingList.ListItem.TABLE_NAME, finalSelection, selectionArgs);
				break;
				
			default:
				throw new IllegalArgumentException("Unknown URI" + uri);
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
	
		ContentValues values;
		Uri insertUri = null;
		
		if(initialValues != null){
			values = new ContentValues(initialValues);
		}
		else{
			values = new ContentValues();
		}
		
		switch(sUriMatcher.match(uri)){
			case LIST:
				if(values.containsKey(ShoppingList.List.COLUMN_NAME_COUNT) == false){
					values.put(ShoppingList.List.COLUMN_NAME_COUNT, 0);
				}
				
				insertUri = insertRecord(
						ShoppingList.List.TABLE_NAME, 
						ShoppingList.List.COLUMN_NAME_NAME,
						ShoppingList.List.CONTENT_ID_URI_BASE,
						values);
				break;
			case LIST_ITEM:
				if(values.containsKey(ShoppingList.ListItem.COLUMN_NAME_COUNT) == false){
					values.put(ShoppingList.ListItem.COLUMN_NAME_COUNT, 0);
				}
				
				insertUri = insertRecord(
						ShoppingList.ListItem.TABLE_NAME, 
						ShoppingList.ListItem.COLUMN_NAME_LIST_ID,
						ShoppingList.ListItem.CONTENT_ID_URI_BASE,
						values);
				break;
			case ITEM:
				insertUri = insertRecord(
						ShoppingList.Item.TABLE_NAME, 
						ShoppingList.Item.COLUMN_NAME_ITEM_NAME, 
						ShoppingList.Item.CONTENT_ID_URI_BASE, 
						values);
				break;
		}
		
		if(insertUri == null)
			throw new SQLException("Failed to insert row into " + uri);
		
		return insertUri;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count;
		String finalSelection;
		
		switch(sUriMatcher.match(uri)){
			case LIST:
				count = db.update(
						ShoppingList.List.TABLE_NAME,
						values,
						selection,
						selectionArgs);
				break;
				
			case LIST_ID:
				String listID = uri.getPathSegments().get(ShoppingList.List.LIST_ID_PATH_POSITION);
				finalSelection = ShoppingList.List._ID + " = " + listID;
				if(selection != null){
					finalSelection += "AND " + selection;
				}
				count = db.update(
						ShoppingList.List.TABLE_NAME,
						values,
						finalSelection,
						selectionArgs);
				break;
			case LIST_ITEM:
				count = db.update(
						ShoppingList.ListItem.TABLE_NAME,
						values,
						selection,
						selectionArgs);
				break;
			case LIST_ITEM_ID:
				String listItemID = uri.getPathSegments().get(ShoppingList.ListItem.ID_PATH_POSITION);
				finalSelection = ShoppingList.ListItem._ID + " = " + listItemID;
				if(selection != null){
					finalSelection += "AND " + selection;
				}
				count = db.update(
						ShoppingList.ListItem.TABLE_NAME,
						values,
						finalSelection,
						selectionArgs);
				
				break;
				
			case ITEM:
				count = db.update(
						ShoppingList.Item.TABLE_NAME,
						values,
						selection,
						selectionArgs);
				
				break;
				
			case ITEM_ID:
				String itemID = uri.getPathSegments().get(ShoppingList.Item.ID_PATH_POSITION);
				finalSelection = ShoppingList.Item._ID + " = " + itemID;
				if(selection != null){
					finalSelection += "AND " + selection;
				}
				count = db.update(
						ShoppingList.ListItem.TABLE_NAME,
						values,
						finalSelection,
						selectionArgs);
				break;
			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public String getType(Uri uri) {
		switch(sUriMatcher.match(uri)){
			case LIST:
				return ShoppingList.List.CONTENT_TYPE;
			case LIST_ID:
				return ShoppingList.List.CONTENT_ITEM_TYPE;
			case LIST_ITEM:
				return ShoppingList.ListItem.CONTENT_TYPE;
			case LIST_ITEM_ID:
				return ShoppingList.ListItem.CONTENT_ITEM_TYPE;
			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		String tableName = null;
		String orderBy = sortOrder;
		int match = sUriMatcher.match(uri); 

		switch(match){
			case LIST:
				qb.setProjectionMap(sListProjectionMap);
				tableName = ShoppingList.List.TABLE_NAME;
				break;
			case LIST_ID:
				tableName = ShoppingList.List.TABLE_NAME;
				qb.setProjectionMap(sListProjectionMap);
				qb.appendWhere(ShoppingList.List._ID + "=" + uri.getPathSegments().get(ShoppingList.List.LIST_ID_PATH_POSITION));
				break;
			case LIST_ITEM:
				tableName = ShoppingList.ListItem.TABLE_NAME;
				qb.setProjectionMap(sListProjectionMap);
				break;
			case LIST_ITEM_ID:
				tableName = ShoppingList.ListItem.TABLE_NAME;
				qb.setProjectionMap(sListProjectionMap);
				qb.appendWhere(ShoppingList.ListItem._ID + "=" + uri.getPathSegments().get(ShoppingList.ListItem.ID_PATH_POSITION));
				break;
			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		
		if(TextUtils.isEmpty(sortOrder)){
			switch(match){
				case LIST:
				case LIST_ID:
					orderBy = ShoppingList.List.DEFAULT_SORT_ORDER;
				break;
				case LIST_ITEM:
				case LIST_ITEM_ID:
					//orderBy = ShoppingList.ListItem.DEFAULT_SORT_ORDER;
					break;
			}
		}
		
		qb.setTables(tableName);

		SQLiteDatabase db = dbHelper.getReadableDatabase();
		
		Cursor c = qb.query(
				db,
				projection,
				selection,
				selectionArgs,
				null,
				null,
				orderBy);
		
		c.setNotificationUri(getContext().getContentResolver(), uri);
		
		return c;
	}

	DatabaseHelper getOpenHelperForTest(){
		return dbHelper;
	}
	
	private Uri insertRecord(String tableName, String columnName, Uri tableUri, ContentValues values){
		
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		Uri uri = null;
		long rowItemID = db.insert(
				tableName, 
				columnName,
				values);
		
		if(rowItemID > 0){
			uri = ContentUris.withAppendedId(tableUri, rowItemID);	
			getContext().getContentResolver().notifyChange(uri, null);
		}
		return uri;
	}
	
}
